package pers.cj.pdos.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import pers.cj.pdos.entity.*;
import pers.cj.pdos.mapper.*;
import pers.cj.pdos.service.IRefundService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import pers.cj.pdos.utils.*;
import pers.cj.pdos.vo.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 退货单会将商品的状态置为待入库，需要仓库管理员进行入库操作 服务实现类
 * </p>
 *
 * @author chenj
 * @since 2019-11-04
 */
@Service
public class RefundServiceImpl extends ServiceImpl<RefundMapper, Refund> implements IRefundService {
    @Autowired
    RefundMapper refundMapper;
    @Autowired
    RefundGoodsMapper refundGoodsMapper;
    @Autowired
    RefundPacketMapper refundPacketMapper;
    @Autowired
    RefundPacketGoodsMapper refundPacketGoodsMapper;
    @Autowired
    GoodsStockMapper goodsStockMapper;
    @Autowired
    SaleMapper saleMapper;
    @Autowired
    SaleGoodsMapper saleGoodsMapper;
    @Autowired
    SalePacketMapper salePacketMapper;
    @Autowired
    ArrearsWaitMapper arrearsWaitMapper;
    @Autowired
    GoodsSnMapper goodsSnMapper;
    @Autowired
    GoodsSnLogMapper goodsSnLogMapper;
    @Autowired
    HouseWaitInMapper houseWaitInMapper;
    @Autowired
    HouseWaitInGoodsMapper houseWaitInGoodsMapper;
    @Autowired
    HouseWaitInPacketMapper houseWaitInPacketMapper;
    @Autowired
    HouseWaitInPacketGoodsMapper houseWaitInPacketGoodsMapper;
    @Autowired
    SettAccountMapper settAccountMapper;


    @Override
    public List<RefundVo> listVo(String companyId,
                                 Integer page,
                                 Integer limit,
                                 Boolean close,
                                 String search,
                                 String no,
                                 String saleNo,
                                 String goodsName,
                                 String remark,
                                 String storeId,
                                 String houseId,
                                 String settAccountId,
                                 String custom,
                                 Date makeTime1,
                                 Date makeTime2,
                                 String userStoreId,
                                 String userId,
                                 Date date1,
                                 Date date2,
                                 Date date,
                                 String makeUserId,
                                 String customId,
                                 Integer status) {
        return refundMapper.listVo(companyId,
                Utils.genPage(page,limit),
                limit,
                close,
                search,
                no,
                saleNo,
                goodsName,
                remark,
                storeId,
                houseId,
                settAccountId,
                custom,
                makeTime1,
                makeTime2,
                userStoreId,
                userId,
                date1,
                date2,
                date,
                makeUserId,
                customId,
                status);
    }

    @Override
    public long count(String companyId,
                      Boolean close,
                      String search,
                      String no,
                      String saleNo,
                      String goodsName,
                      String remark,
                      String storeId,
                      String houseId,
                      String settAccountId,
                      String custom,
                      Date makeTime1,
                      Date makeTime2,
                      String userStoreId,
                      String userId,
                      Date date1,
                      Date date2,
                      Date date,
                      String makeUserId,
                      String customId,
                      Integer status) {
        return refundMapper.count(companyId,
                close,
                search,
                no,
                saleNo,
                goodsName,
                remark,
                storeId,
                houseId,
                settAccountId,
                custom,
                makeTime1,
                makeTime2,
                userStoreId,
                userId,
                date1,
                date2,
                date,
                makeUserId,
                customId,
                status);
    }

    @Override
    public RefundVo getVoById(String id) {
        return refundMapper.getVoById(id);
    }

    @Override
    public List<RefundVo> listVoByIds(List<String> ids) {
        return refundMapper.listVoByIds(ids);
    }

    @Override
    public boolean checkNo(String no, String companyId) {
        return refundMapper.selectCount(new QueryWrapper<Refund>().eq("company_id",companyId).eq("no",no)) > 0;
    }

    @Override
    public void insert(BusinessSet businessSet, Refund refund,
                       List<RefundGoods> refundGoodsList, List<GoodsSn> goodsSnList,List<GoodsSnLog> goodsSnLogList,
                       List<RefundPacket> refundPacketList, List<RefundPacketGoods> refundPacketGoodsList) {
        refundMapper.insert(refund);
        if (!Utils.isEmpty(refundGoodsList)) {
            refundGoodsMapper.insertBatch(refundGoodsList);
        }
        if (!Utils.isEmpty(refundPacketList)) {
            refundPacketMapper.insertBatch(refundPacketList);
            refundPacketGoodsMapper.insertBatch(refundPacketGoodsList);
        }

        RefundVo refundVo = refundMapper.getVoById(refund.getId());

        //余额-
        settAccountMapper.addBalance(refundVo.getRealAmt().negate(), refundVo.getSettAccountId());

        //收款单处理
        processArrearsWait(1, refundVo);
        //处理关联的销售单
        processSale(1,refundVo);

        if (!PdosUtils.houseInOut(businessSet)) {
            //未启用出入库管理，直接添加库存
            processGoodsStock(1, refundVo);
            if (!Utils.isEmpty(goodsSnList)) {
                goodsSnMapper.insertBatch(goodsSnList);
                goodsSnLogMapper.insertBatch(goodsSnLogList);
            }
        } else {
            //启用库存管理，则添加待入库单数据
            processHouseWaitIn(1,refundVo);
        }
    }

    @Override
    public void close(Refund refund) {
        RefundVo vo = refundMapper.getVoById(refund.getId());

        //余额+
        settAccountMapper.addBalance(vo.getRealAmt(), vo.getSettAccountId());

        //直接入库的进货单，则需要去除相应的库存和sn。
        if (vo.getStatus() == 1) {
            processGoodsStock(2, vo);

            //关闭进货单需要sn号需要处与出库状态
            List<GoodsSn> list = PdosUtils.genGoodsSnList(vo.getRefundGoodsVoList());
            if (!Utils.isEmpty(list)) {
                goodsSnMapper.outByList(vo.getHouseId(), list);
            }
        } else {
            processHouseWaitIn(2,vo);
        }

        //处理管理销售单
        processSale(2,vo);

        //处理应付欠款
        processArrearsWait(2,vo);

        Refund temp = new Refund();
        temp.setId(vo.getId());
        temp.setClose(true);
        refundMapper.updateById(temp);
    }

    @Override
    public boolean checkClose(Refund refund) {
        return refundMapper.selectCount(new QueryWrapper<Refund>().eq("id",refund.getId()).eq("close",true))  > 0;
    }


    /**
     * 待入库单处理
     * @param type 1-新增销售退货 2作废销售退货
     * @param refundVo
     */
    private void processHouseWaitIn(int type, RefundVo refundVo) {
        if (type == 2) {
            //更新待入库单的关联单据的关闭状态
            HouseWaitIn houseWaitIn = new HouseWaitIn();
            houseWaitIn.setClose(true);
            houseWaitInMapper.update(houseWaitIn, new QueryWrapper<HouseWaitIn>().eq("refund_id", refundVo.getId()));
            return;
        }

        HouseWaitIn houseWaitIn = new HouseWaitIn();
        houseWaitIn.setId(UuidUtils.getUUID());
        houseWaitIn.setRefundId(refundVo.getId());
        houseWaitIn.setHouseId(refundVo.getHouseId());
        houseWaitIn.setClose(false);
        houseWaitIn.setStatus(1);//待入库
        houseWaitIn.setType(2);//设置类型为进货
        houseWaitIn.setCompanyId(refundVo.getCompanyId());
        houseWaitIn.setTime(refundVo.getTime());
        houseWaitInMapper.insert(houseWaitIn);


        BigDecimal zero = new BigDecimal("0");

        if (!Utils.isEmpty(refundVo.getRefundGoodsVoList())) {
            List<HouseWaitInGoods> houseWaitInGoodsList = new ArrayList<>();
            for (RefundGoodsVo refundGoodsVo : refundVo.getRefundGoodsVoList()) {
                HouseWaitInGoods houseWaitInGoods = new HouseWaitInGoods();
                houseWaitInGoods.setId(UuidUtils.getUUID());
                houseWaitInGoods.setHouseWaitInId(houseWaitIn.getId());
                houseWaitInGoods.setRefundGoodsId(refundGoodsVo.getId());
                houseWaitInGoods.setGoodsId(refundGoodsVo.getGoodsId());
                houseWaitInGoods.setHasInNumber(zero);
                houseWaitInGoods.setWaitInNumber(refundGoodsVo.getNumber());
                houseWaitInGoods.setNumber(refundGoodsVo.getNumber());
                houseWaitInGoods.setUnitId(refundGoodsVo.getUnitId());
                houseWaitInGoods.setTimes(refundGoodsVo.getTimes());
                houseWaitInGoods.setCompanyId(refundVo.getCompanyId());
                houseWaitInGoodsList.add(houseWaitInGoods);
            }
            houseWaitInGoodsMapper.insertBatch(houseWaitInGoodsList);
        }

        if (!Utils.isEmpty(refundVo.getRefundPacketVoList())) {
            List<HouseWaitInPacket> houseWaitInPacketList = new ArrayList<>();
            List<HouseWaitInPacketGoods> houseWaitInPacketGoodsList = new ArrayList<>();

            for (RefundPacketVo vo : refundVo.getRefundPacketVoList()) {
                HouseWaitInPacket houseWaitInPacket = new HouseWaitInPacket();
                houseWaitInPacket.setId(UuidUtils.getUUID());
                houseWaitInPacket.setHouseWaitInId(houseWaitIn.getId());
                houseWaitInPacket.setRefundPacketId(vo.getId());
                houseWaitInPacket.setPacketId(vo.getPacketId());
                houseWaitInPacket.setPacketName(vo.getPacketName());
                houseWaitInPacket.setPacketNo(vo.getPacketNo());
                houseWaitInPacket.setHasInNumber(new BigDecimal(0));
                houseWaitInPacket.setWaitInNumber(vo.getNumber());
                houseWaitInPacket.setNumber(vo.getNumber());
                houseWaitInPacket.setCompanyId(refundVo.getCompanyId());
                houseWaitInPacketList.add(houseWaitInPacket);

                for (RefundPacketGoodsVo packetGoodsVo : vo.getPacketGoodsVoList()) {
                    HouseWaitInPacketGoods entity = new HouseWaitInPacketGoods();
                    entity.setId(UuidUtils.getUUID());
                    entity.setHouseWaitInId(houseWaitIn.getId());
                    entity.setHouseWaitInPacketId(houseWaitInPacket.getId());
                    entity.setPacketId(packetGoodsVo.getPacketId());
                    entity.setGoodsId(packetGoodsVo.getGoodsId());
                    entity.setNumber(packetGoodsVo.getNumber());
                    entity.setUnitId(packetGoodsVo.getUnitId());
                    entity.setTimes(packetGoodsVo.getTimes());
                    entity.setPrice(packetGoodsVo.getPrice());
                    entity.setAmount(packetGoodsVo.getAmount());
                    entity.setCompanyId(refundVo.getCompanyId());
                    houseWaitInPacketGoodsList.add(entity);
                }
            }

            houseWaitInPacketMapper.insertBatch(houseWaitInPacketList);
            houseWaitInPacketGoodsMapper.insertBatch(houseWaitInPacketGoodsList);
        }

    }


    /**
     *
     * 处理库存
     * @param type 1新增销售退货单 2作废销售退货单
     * @param refundVo
     */
    private void processGoodsStock(int type, RefundVo refundVo) {
        List<GoodsStock> goodsStockList = new ArrayList<>();
        GoodsUtil goodsUtil = new GoodsUtil(refundVo.getHouseId(), refundVo.getRefundGoodsVoList(), refundVo.getRefundPacketVoList());
        Map<String, BigDecimal> goodsNumberMap = goodsUtil.getAllGoodsNumberMap();
        for ( Map.Entry<String,BigDecimal> entry: goodsNumberMap.entrySet()) {
            String goodsId = entry.getKey();
            BigDecimal number = entry.getValue();
            if (type == 2) {
                //销售退货作废，减少库存；销售退货则是增加库存
                number = number.negate();
            }

            GoodsStock goodsStock = new GoodsStock();
            goodsStock.setId(UuidUtils.getUUID());
            goodsStock.setGoodsId(goodsId);
            goodsStock.setHouseId(refundVo.getHouseId());
            goodsStock.setNum(number);
            goodsStock.setCompanyId(refundVo.getCompanyId());
            goodsStock.setTime(new Date());
            goodsStockList.add(goodsStock);
        }

        goodsStockMapper.insertBatch(goodsStockList);
    }

    /**
     * 处理应收款
     * @param type 1新增销售退单 2作废销售退货单
     * @param vo
     */
    private void processSale(int type, RefundVo vo) {
        if (Utils.isEmpty(vo.getSaleId())) {
            return;
        }

        if (!Utils.isEmpty(vo.getRefundGoodsVoList())) {
            List<SaleGoods> saleGoodsList = new ArrayList<>();
            for (RefundGoodsVo refundGoodsVo : vo.getRefundGoodsVoList()) {
                SaleGoods saleGoods = new SaleGoods();
                saleGoods.setId(refundGoodsVo.getSaleGoodsId());
                saleGoods.setSaleId(vo.getSaleId());
                saleGoods.setNumber(refundGoodsVo.getNumber());
                BigDecimal number = refundGoodsVo.getNumber();
                if (type == 2) {
                    //作废销售退货单，则需要减去销售商品表对于的退货数量
                    number = number.negate();
                }
                saleGoods.setRefundNumber(number);
                saleGoods.setGoodsId(refundGoodsVo.getGoodsId());
                saleGoods.setUnitId(refundGoodsVo.getUnitId());
                saleGoods.setTimes(refundGoodsVo.getTimes());
                saleGoods.setPrice(refundGoodsVo.getPrice());
                saleGoods.setAmount(refundGoodsVo.getAmount());
                saleGoods.setAfterDiscountAmt(refundGoodsVo.getAmount());
                saleGoods.setProfits(new BigDecimal(0));
                saleGoods.setCompanyId(vo.getCompanyId());
                saleGoodsList.add(saleGoods);
            }
            saleGoodsMapper.insertBatch(saleGoodsList);
        }

        if (!Utils.isEmpty(vo.getRefundPacketVoList())) {
            List<SalePacket> salePacketList = new ArrayList<>();
            for (RefundPacketVo refundPacketVo : vo.getRefundPacketVoList()) {
                SalePacket salePacket = new SalePacket();
                salePacket.setId(refundPacketVo.getSalePacketId());
                salePacket.setSaleId(vo.getSaleId());
                salePacket.setNumber(refundPacketVo.getNumber());
                BigDecimal number = refundPacketVo.getNumber();
                if (type == 2) {
                    //作废销售退货单，则需要减去销售商品表对于的退货数量
                    number = number.negate();
                }
                salePacket.setRefundNumber(number);
                salePacket.setPacketId(refundPacketVo.getPacketId());
                salePacket.setPacketNo(refundPacketVo.getPacketNo());
                salePacket.setPacketName(refundPacketVo.getPacketName());
                salePacket.setPrice(refundPacketVo.getPrice());
                salePacket.setAmount(refundPacketVo.getAmount());
                salePacket.setAfterDiscountAmt(refundPacketVo.getAmount());
                salePacket.setProfits(new BigDecimal(0));
                salePacket.setCompanyId(vo.getCompanyId());
                salePacketList.add(salePacket);
            }
            salePacketMapper.insertBatch(salePacketList);
        }



        Sale temp = new Sale();
        temp.setId(vo.getSaleId());

        long totalRefundNumber = saleGoodsMapper.countRefundNumber(vo.getSaleId()) + salePacketMapper.countRefundNumber(vo.getSaleId());
        long number = saleGoodsMapper.countNumber(vo.getSaleId())  + salePacketMapper.countNumber(vo.getSaleId());
        if (totalRefundNumber == 0) {
            //未退货
            temp.setRefund(0);
        } else if(totalRefundNumber < number) {
            //部分退货
            temp.setRefund(1);
        } else {
            //全部退货
            temp.setRefund(2);
        }
        saleMapper.updateById(temp);
    }


    /**
     * 处理应收款
     * @param type 1新增销售退单 2作废销售退货单
     * @param vo
     */
    private void processArrearsWait(int type, RefundVo vo) {
        if (vo.getTotalAmt().compareTo(vo.getRealAmt()) == 1) {
            //总计金额大于实收金额，此时产生应收款
            ArrearsWait dbArrearsWait = arrearsWaitMapper.selectOne(new QueryWrapper<ArrearsWait>().eq("custom_id",vo.getCustomId()).eq("company_id", vo.getCompanyId()));
            if (dbArrearsWait == null) {
                if (type == 1) {
                    ArrearsWait arrearsWait = new ArrearsWait();
                    arrearsWait.setId(UuidUtils.getUUID());
                    arrearsWait.setCustomId(vo.getCustomId());
                    arrearsWait.setCompanyId(vo.getCompanyId());
                    BigDecimal total = vo.getTotalAmt().subtract(vo.getRealAmt()).negate();//因为是退货，所以应收金额实负数
                    arrearsWait.setTotal(total);
                    arrearsWait.setHasIn(new BigDecimal("0"));
                    arrearsWait.setWaitIn(arrearsWait.getTotal());
                    arrearsWait.setDiscount(new BigDecimal("0"));
                    arrearsWaitMapper.insert(arrearsWait);
                }
            } else {
                BigDecimal total = vo.getTotalAmt().subtract(vo.getRealAmt()).negate();//因为是退货，所以应收金额实负数
                if (type == 1) {
                    dbArrearsWait.setTotal(total.add(dbArrearsWait.getTotal()));
                    dbArrearsWait.setWaitIn(total.add(dbArrearsWait.getWaitIn()));
                } else {
                    dbArrearsWait.setTotal(dbArrearsWait.getTotal().subtract(total));
                    dbArrearsWait.setWaitIn(dbArrearsWait.getWaitIn().subtract(total));
                }

                arrearsWaitMapper.updateById(dbArrearsWait);
            }
        }
    }
}
